package com.apes.framework.plugin.fsm.util;

import com.alibaba.fastjson.JSONObject;
import com.apes.framework.plugin.express.FuncAlias;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.apes.framework.util.EventUtil.sendSynEvent;
import static com.apes.framework.util.MapUtil.mapper;

/**
 * 功能：Fsm Util
 *
 * @author xul
 * @create 2020-10-28 11:37
 */
@Component
public class FsmUtil {
    private static List<Function> functions = initTimeFunctions();

    /**
     * 执行表达式
     **/
    @SneakyThrows
    public static <T> T execute(String express, Map context) {
        return (T) FsmExpressEngine.getInstance().execute(express, context);
    }

    /**
     * 编译脚本，查询外部需要定义的变量和函数
     **/
    @SneakyThrows
    public static String[] getOutVarNames(String express) {
        return FsmExpressEngine.getInstance().getExpressRunner().getOutVarNames(express);
    }

    private static List<Function> initTimeFunctions() {
        List<Function> functions = new ArrayList<>();
        functions.add(expression -> {
            String value = getVariable("()(.+?)(分钟之后)", (String) expression); /**格式：...分钟之后 **/
            if (value == null) return null;
            return new TaskParam(Integer.valueOf(value), 1, Calendar.MINUTE, "increase");
        });

        functions.add(expression -> {
            String value = getVariable("()(.+?)(小时之后)", (String) expression); /**格式：...小时之后 **/
            if (value == null) return null;
            return new TaskParam(Integer.valueOf(value), 1, Calendar.HOUR_OF_DAY, "increase");
        });

        functions.add(expression -> {
            String value = getVariable("()(.+?)(天之后)", (String) expression); /**格式：...天之后 **/
            if (value == null) return null;
            return new TaskParam(Integer.valueOf(value), 1, Calendar.DATE, "increase");
        });

        functions.add(expression -> {
            String value = getVariable("(每)(.+?)(分钟)", (String) expression); /**格式：每...分钟 **/
            if (value == null) return null;
            return new TaskParam(Integer.valueOf(value), Integer.MAX_VALUE, Calendar.MINUTE, "increase");
        });

        functions.add(expression -> {
            String value = getVariable("(每)(.+?)(小时)", (String) expression); /**格式：每...小时 **/
            if (value == null) return null;
            return new TaskParam(Integer.valueOf(value), Integer.MAX_VALUE, Calendar.HOUR_OF_DAY, "increase");
        });

        functions.add(expression -> {
            String value = getVariable("(每)(.+?)(天)", (String) expression); /**格式：每...天 **/
            if (value == null) return null;
            return new TaskParam(Integer.valueOf(value), Integer.MAX_VALUE, Calendar.DATE, "increase");
        });

        functions.add(expression -> {
            String value = getVariable("(当日)(.+?)(点)", (String) expression); /**格式：当日...点 **/
            if (value == null) return null;
            return new TaskParam(Integer.valueOf(value), 1, Calendar.HOUR_OF_DAY, "time-point");
        });

        functions.add(expression -> {
            String value = getVariable("(每日)(.+?)(点)", (String) expression); /**格式：每日...点 **/
            if (value == null) return null;
            return new TaskParam(Integer.valueOf(value), Integer.MAX_VALUE, Calendar.HOUR_OF_DAY, "time-point");
        });
        return functions;
    }

    private static String getVariable(String regex, String target) {
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(target);
        if (matcher.find()) {
            return matcher.group(2).trim();
        }
        return null;
    }

    /**
     * 计算时间
     **/
    @FuncAlias(name = "计算时间")
    public TaskParam calcTime(Date baseTime, String expression) {
        for (Function f : functions) {
            TaskParam taskParam = (TaskParam) f.apply(expression);
            if (taskParam != null) {
                taskParam.calc(baseTime);
                return taskParam;
            }
        }
        throw new RuntimeException("时间计算错误！");
    }

    @FuncAlias(name = "发送消息")
    public void sendMessage(List<String> users, String message) {
        sendSynEvent(this, "event:wf.carbonCopy", mapper(
                "sourceBusinessType", "sourceBusinessType",
                "sourceBusinessKey", message,
                "operate", "发送消息",
                "content", "发送消息",
                "from_id", 1,
                "to_id", users.stream().map(userId -> {
                    JSONObject jo = new JSONObject();
                    jo.put("id", userId);
                    return jo;
                }).collect(Collectors.toList()),
                "processDefinitionName", "发送消息",
                "formId", "",
                "api", "",
                "checked", false
        ));
    }

    public List<String> getFuncAlias() {
        return FsmExpressEngine.getInstance().getFuncAlias();
    }
}
